<?php

namespace app\admin\controller\yungift;

use addons\yungift\library\Super;
use app\common\controller\Backend;
use \app\admin\model\yungift\Group;
use \app\admin\model\yungift\Member as MemberModel;
use \addons\yungift\model\ImportLog as ImportLogModel;
use fast\Random;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use think\Exception;
use \addons\yungift\model\Config;

/**
 * 成员模块
 */
class Member extends Backend
{
    /**
     * @var MemberModel
     */
    protected $model;

    // 联表查询，解决字段冲突
    protected $relationSearch = true;

    // 分组
    protected $groupMap = [];

    // 初始化
    public function _initialize()
    {
        parent::_initialize();
        $this->model = new MemberModel();

        // 分组
        $groupList = Group::getTreeList();
        $groupMap = ['0' => '未分组'];
        foreach ($groupList as $item) {
            $groupMap[$item['id']] = $item['name'];
        }
        $this->groupMap = $groupMap;
        $this->view->assign('groupMap', $this->groupMap);
        $this->assignconfig('groupMap', $groupMap);

        // 状态
        $this->view->assign('statusList', $this->model::getStatusList());
        $this->assignconfig('statusList', $this->model::getStatusList());

        // 性别
        $this->view->assign('genderList', $this->model::getGenderList());
        $this->assignconfig('genderList', $this->model::getGenderList());
    }

    /**
     * 查看
     */
    public function index()
    {
        if ($this->request->isAjax()) {
            // 重载查询条件
            $filter = $this->request->get('filter');
            $op = $this->request->get('op');
            list($filter, $op) = $this->formatFilterOp($filter, $op);
            $this->request->get(['filter' => $filter, 'op' => $op]);

            // 通用查询条件
            list($where, $sort, $order, $offset, $limit) = $this->buildparams();
            $list = $this->model->with(['group_Data', 'user_data'])->where($where)
                ->order($sort, $order)->limit($offset, $limit)->paginate($limit);
            foreach ($list as $item) {
                $item->append(['code_mix'])->hidden(['code']);
            }
            $result = array(
                'total' => $list->total(),
                'rows'  => $list->items(),
            );

            return json($result);
        }

        return $this->view->fetch();
    }

    /**
     * 格式化查询条件
     *
     * @param $filter
     * @param $op
     * @return array
     */
    private function formatFilterOp($filter, $op)
    {
        $filter = json_decode($filter, true);
        $op = json_decode($op, true);
        if (array_key_exists('hasCode', $filter)) {
            if ($filter['hasCode']) {
                $filter['code'] = '';
                $op['code'] = '<>';
            } else {
                $filter['code'] = '';
                $op['code'] = '=';
            }
            unset($filter['hasCode'], $op['hasCode']);
        }
        if (array_key_exists('hasBind', $filter)) {
            if ($filter['hasBind']) {
                $filter['user_id'] = 0;
                $op['user_id'] = '<>';
            } else {
                $filter['user_id'] = 0;
                $op['user_id'] = '=';
            }
            unset($filter['hasBind'], $op['hasBind']);
        }
        if (array_key_exists('group_id', $filter)) {
            if ($filter['group_id']) {
                $filter['group_id'] = Group::getRelationIds($filter['group_id']);
                $op['group_id'] = 'in';
            } else {
                $filter['group_id'] = 0;
                $op['group_id'] = '=';
            }
        }

        return [json_encode($filter), json_encode($op)];
    }

    /**
     * 详情
     */
    public function detail($ids)
    {
        if (! $row = $this->model::get(['id' => $ids])) {
            $this->error(__('No Results were found'));
        }
        if ($this->request->isAjax()) {
            $this->success('Ajax请求成功', null, ['id' => $ids]);
        }
        $this->view->assign('row', $row);

        return $this->view->fetch();
    }

    // 生成登录码
    public function createCode()
    {
        // 超时、超内存设置
        ini_set('memory_limit', '1024M');
        ini_set('max_execution_time', '0');

        $search = $this->request->post('search');
        $ids = $this->request->post('ids');
        $filter = $this->request->post('filter');
        $op = $this->request->post('op');
        $codeCreate = $this->request->post('code_create');
        $resetCode = $this->request->post('reset_code');
        list($filter, $op) = $this->formatFilterOp($filter, $op);

        // 获取条件
        $whereIds = $ids === 'all' ? '1=1' : ['id' => ['in', explode(',', $ids)]];
        $this->request->get(['search' => $search, 'ids' => $ids, 'filter' => $filter, 'op' => $op]);
        list($where, $sort, $order, $offset, $limit) = $this->buildparams();

        $counter = [];

        // 查询数据
        $this->model
            ->where($where)
            ->where($whereIds)
            ->chunk(100, function ($items) use (&$counter, $codeCreate, $resetCode) {
                foreach ($items as $item) {
                    if (empty($resetCode) && $item->code) {
                        Super::counter($counter, '忽略已有登录码');
                        continue;
                    }
                    $code = null;
                    if ($codeCreate === 'number_suffix') {
                        if ($item->number) {
                            $code = substr($item->number, -6);  // 取编号的后6位
                        } else {
                            Super::counter($counter, '没有编号');
                        }
                    } elseif ($codeCreate === 'phone_suffix') {
                        if ($item->phone) {
                            $code = substr($item->phone, -6);  // 取手机号的后6位
                        } else {
                            Super::counter($counter, '没有手机号');
                        }
                    } elseif ($codeCreate === 'string_rand') {  // 随机8位数
                        $code = strtolower(Random::alnum(8));
                    }
                    if ($code) {
                        Super::counter($counter, '生成登录码成功');
                        $item->code = md5($code);
                        $item->init_code = $code;
                        $item->save();
                    }
                }
            });

        // 导入结果
        $content = ['处理成功<br>'];
        foreach ($counter as $key => $value) {
            $hasError = false;
            if (! in_array($key, ['忽略已有登录码', '生成登录码成功'])) {
                $hasError = true;
            }
            $cont = $key . '： ' . $value . '条';
            if ($hasError) {
                $cont = '<b style="color: yellow;">' . $cont . '</b>';
            }
            $content[] = $cont;
        }
        $content = implode('<br>', $content);
        $this->success($content);
    }

    /**
     * 数据导入
     *
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function import()
    {
        // 超时、超内存设置
        ini_set('memory_limit', '1024M');
        ini_set('max_execution_time', '0');

        // 获取文件路径
        $file = $this->request->request('file');
        if (! $file) {
            $this->error(__('Parameter %s can not be empty', 'file'));
        }
        $filePath = ROOT_PATH . DS . 'public' . DS . $file;
        if (! is_file($filePath)) {
            $this->error(__('No results were found'));
        }

        // 新增导入结果
        ImportLogModel::create([
            'scene'       => ImportLogModel::SCENE_MEMBER,
            'import_file' => $file,
            'status'      => ImportLogModel::STATUS_HANDLE
        ]);

        // 实例化reader，并读取文件
        $ext = pathinfo($filePath, PATHINFO_EXTENSION);
        if ($ext !== 'xlsx') {
            $this->error(__('Unknown data format'));
        }
        $reader = new Xlsx();
        if (! $spreadsheet = $reader->load($filePath)) {
            $this->error(__('Unknown data format'));
        }
        $currentSheet = $spreadsheet->getSheet(0);  // 读取文件中的第一个工作表
        $allColumn = $currentSheet->getHighestDataColumn();  // 取得最大的列号
        $allRow = $currentSheet->getHighestRow();  // 取得一共有多少行
        $maxColumnNumber = Coordinate::columnIndexFromString($allColumn);  // 取得最大的列数字
        if ($allRow <= 2) {
            $this->error(__('No rows were updated'));
        }
        $firstHead = $currentSheet->getCellByColumnAndRow(1, 2)->getValue();
        if ($firstHead !== '一级分组') {
            $this->error(__('数据表头不对'));
        }

        $counter = [];
        try {
            // 获取数据
            $dataList = [];
            for ($currentRow = 3; $currentRow <= $allRow; $currentRow++) {
                $values = [];
                for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
                    $val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
                    $values[] = is_null($val) ? '' : trim($val);
                }
                $dataList[] = $values;
            }

            // 设置标题
            $this->setSheetCellValue($currentSheet, -1, '导入结果');
            $currentSheet->getCellByColumnAndRow(10, 2)->getStyle()->applyFromArray([
                'font'      => [
                    'name'  => 'Arial',
                    'color' => ['rgb' => '000000'],
                    'size'  => 12,
                    'bold'  => true
                ],
                'alignment' => [
                    'horizontal' => Alignment::HORIZONTAL_CENTER,
                    'vertical'   => Alignment::VERTICAL_CENTER,
                ]
            ]);

            // 登录方式
            $loginMethods = Config::getGroupAttribute(Config::GROUP_BASE, 'login_methods');

            // 处理数据
            // 列对应关系：0=一级分组，1=二级分组，2=三级分组，3=姓名，4=编号，5=性别，6=手机号，7=登录码，8=备注
            foreach ($dataList as $index => $item) {
                // 保存分组，支持最多3级
                $groupId = 0;
                $parentId = 0;
                foreach (array_slice($item, 0, 3) as $key => $value) {
                    if (empty($value)) {
                        if ($key === 0) {
                            $this->setSheetCellValue($currentSheet, $index, '首列为空', 1, $counter);
                        }
                        break;
                    }
                    if (! $group = Group::get(['name' => $value, 'parent_id' => $parentId])) {
                        $group = new Group();
                        $group->data([
                            'scenario'  => 'add',
                            'name'      => $value,
                            'parent_id' => $parentId,
                            'status'    => Group::STATUS_NORMAL
                        ]);
                        $group->allowField(true)->save();
                    }
                    $parentId = $group->id;
                    $groupId = $group->id;
                }
                if (empty($item[3])) {
                    $this->setSheetCellValue($currentSheet, $index, '姓名为空', 1, $counter);
                    continue;
                }

                // 保存用户
                $where = [];
                if (strpos($loginMethods, 'phone_captcha') !== false
                    || strpos($loginMethods, 'wechat_phone') !== false) {
                    $where['phone'] = $item[6];
                } else {
                    if ($item[4]) {
                        $where['number'] = $item[4];
                    } elseif ($item[6]) {
                        $where['phone'] = $item[6];
                    } else {
                        $where['name'] = $item[3];
                        $where['group_id'] = $groupId;
                    }
                }
                if (! $member = MemberModel::get($where)) {
                    $member = new MemberModel();
                    $member->status = MemberModel::STATUS_NORMAL;
                }
                $member['name'] = $item[3];
                $member->number = $item[4];
                $gender = MemberModel::GENDER_NONE;
                if ($item[5] === '男') {
                    $gender = MemberModel::GENDER_MALE;
                } elseif ($item[5] === '女') {
                    $gender = MemberModel::GENDER_FEMALE;
                }
                $member->gender = $gender;
                $member->phone = $item[6];
                $member->note = $item[8];
                $member->group_id = $groupId;

                // 校验手机号
                if (strpos($loginMethods, 'phone_captcha') !== false
                    || strpos($loginMethods, 'wechat_phone') !== false) {
                    if (empty($member->phone)) {
                        $this->setSheetCellValue($currentSheet, $index, '手机号为空', 1, $counter);
                        continue;
                    }
                    $memberIds = MemberModel::where(['phone' => $member->phone])->column('id');
                    if ($memberIds && (empty($member['id']) || array_diff($memberIds, [$member['id']]))) {
                        $this->setSheetCellValue($currentSheet, $index, '手机号已存在', 1, $counter);
                        continue;
                    }
                }

                // 生成登录码
                if (strpos($loginMethods, 'name_code') !== false
                    || strpos($loginMethods, 'number_code') !== false) {
                    if (empty($member['code'])) {
                        $code = $item[7];
                        if (! $code) {
                            $codeCreate = Config::getGroupAttribute(Config::GROUP_BASE, 'code_create');
                            if ($codeCreate === 'number_suffix') {
                                if (empty($member->number)) {
                                    $this->setSheetCellValue($currentSheet, $index, '编号为空，登录码无法生成', 1, $counter);
                                    continue;
                                }
                                $code = substr($member->number, -6);  // 取编号的后6位
                            } elseif ($codeCreate === 'phone_suffix') {
                                if (empty($member->phone)) {
                                    $this->setSheetCellValue($currentSheet, $index, '手机号为空，登录码无法生成', 1, $counter);
                                    continue;
                                }
                                $code = substr($member->phone, -6);  // 取手机号的后6位
                            } elseif ($codeCreate === 'string_rand') {
                                $code = strtolower(Random::alnum(8));  // 随机8位数
                            }
                        }
                        if ($code) {
                            $member->code = md5($code);
                            $member->init_code = $code;
                            $memberIds = MemberModel::where(['name' => $member['name'], 'code' => $member->code])
                                ->column('id');
                            if ($memberIds && (empty($member['id']) || array_diff($memberIds, [$member['id']]))) {
                                $this->setSheetCellValue($currentSheet, $index, '姓名和登录码已存在', 1, $counter);
                                continue;
                            }
                        }
                    } else {
                        $this->setSheetCellValue($currentSheet, $index, '登录码已存在', -1, $counter);
                    }
                }

                $inert = empty($member->id);
                $member->save();
                if ($inert) {
                    $this->setSheetCellValue($currentSheet, $index, '新增数据', 0, $counter);
                } else {
                    $this->setSheetCellValue($currentSheet, $index, '更新数据', 0, $counter);
                }
            }

            // 生成excel文件
            $filePath = DS . 'uploads' . DS . date('Ymd') . DS . Random::alnum(32) . '.xlsx';
            $objWriter = IOFactory::createWriter($spreadsheet, 'Xlsx');
            $objWriter->save(ROOT_PATH . 'public' . $filePath);

            // 更新导入结果
            ImportLogModel::update([
                'result_file' => $filePath,
                'status'      => ImportLogModel::STATUS_FINISH
            ], [
                'scene'       => ImportLogModel::SCENE_MEMBER,
                'import_file' => $file,
            ]);
        } catch (Exception $exception) {
            $this->error($exception->getMessage());
        }

        // 导入结果
        $content = ['处理成功<br>'];
        foreach ($counter as $key => $value) {
            $hasError = false;
            if (! in_array($key, ['新增数据', '更新数据'])) {
                $key .= '，导入失败';
                $hasError = true;
            }
            $cont = $key . '： ' . $value . '条';
            if ($hasError) {
                $cont = '<b style="color: yellow;">' . $cont . '</b>';
            }
            $content[] = $cont;
        }
        $content = implode('<br>', $content);
        $exportResult = $filePath;
        $content .= '<br><br><a href="' . $exportResult . '" target="_blank" style="color: yellow;"><b><i class="fa fa-download"></i> 下载导入结果</b></a>';

        $this->success($content);
    }

    /**
     * 设置表格内容
     *
     * @param $workSheet
     * @param $index
     * @param $value
     */
    private function setSheetCellValue(&$workSheet, $index, $value, $level = 0, &$counter = [])
    {
        $col = 10;
        if ($level != -1) {
            Super::counter($counter, $value);
        }
        if ($oldValue = $workSheet->getCellByColumnAndRow($col, $index + 3)->getValue()) {
            $value = $oldValue . '；' . $value;
        }
        $workSheet->setCellValueByColumnAndRow($col, $index + 3, $value);
        if (! $oldValue) {
            $workSheet->getCellByColumnAndRow($col, $index + 3)->getStyle()->applyFromArray([
                'font'      => [
                    'name'  => 'Arial',
                    'color' => ['rgb' => $level > 1 ? 'f75544' : '000000'],
                    'size'  => 12,
                ],
                'alignment' => [
                    'horizontal' => Alignment::HORIZONTAL_CENTER,
                    'vertical'   => Alignment::VERTICAL_CENTER,
                ]
            ]);
        }
    }

    // 导出数据
    public function export()
    {
        // 超时、超内存设置
        ini_set('memory_limit', '1024M');
        ini_set('max_execution_time', '0');

        if ($this->request->isPost()) {
            // 重载查询条件
            $search = $this->request->post('search');
            $ids = $this->request->post('ids');
            $filter = $this->request->post('filter');
            $op = $this->request->post('op');
            $columns = $this->request->post('columns');
            list($filter, $op) = $this->formatFilterOp($filter, $op);

            // 初始化表
            $spreadsheet = new Spreadsheet();
            $worksheet = $spreadsheet->setActiveSheetIndex(0);
            $worksheet->getDefaultRowDimension()->setRowHeight(25);  // 设置默认行高
            $worksheet->getDefaultColumnDimension()->setAutoSize(true);  // 设置自动宽

            // 设置标题
            foreach ([
                         'ID',
                         '一级分组',
                         '二级分组',
                         '三级分组',
                         '姓名',
                         '编号',
                         '性别',
                         '手机号',
                         '登录码',
                         '是否绑定',
                         '备注',
                         '状态',
                         '新增时间'
                     ] as $key => $value) {
                $worksheet->setCellValueByColumnAndRow($key + 1, 1, __($value));
                $worksheet->getCellByColumnAndRow($key + 1, 1)->getStyle()->applyFromArray([
                    'font'      => [
                        'name'  => 'Arial',
                        'color' => ['rgb' => '000000'],
                        'size'  => 12,
                        'bold'  => true
                    ],
                    'alignment' => [
                        'horizontal' => Alignment::HORIZONTAL_CENTER,
                        'vertical'   => Alignment::VERTICAL_CENTER,
                    ]
                ]);
            }


            // 获取条件
            $whereIds = $ids === 'all' ? '1=1' : ['id' => ['in', explode(',', $ids)]];
            $this->request->get(['search' => $search, 'ids' => $ids, 'filter' => $filter, 'op' => $op]);
            list($where, $sort, $order, $offset, $limit) = $this->buildparams();

            // 查询数据
            $row = 1;
            $this->model
                ->where($where)
                ->where($whereIds)
                ->chunk(100, function ($items) use (&$row, &$worksheet) {
                    foreach ($items as $item) {
                        $row++;
                        $col = 1;
                        $userLevelGroups = Group::getUserLevelGroups($item->group_id, [], false);
                        $userLevelGroups = array_reverse($userLevelGroups);
                        $userLevelGroups = array_values($userLevelGroups);
                        $values = Super::arrayGetSet($item, [
                            'id',
                            'group_1'    => function ($item) use ($userLevelGroups) {
                                return $userLevelGroups[0]['name'] ?? '';
                            },
                            'group_2'    => function ($item) use ($userLevelGroups) {
                                return $userLevelGroups[1]['name'] ?? '';
                            },
                            'group_3'    => function ($item) use ($userLevelGroups) {
                                return $userLevelGroups[2]['name'] ?? '';
                            },
                            'name',
                            'number',
                            'gender_text',
                            'phone',
                            'code'       => function ($item) {
                                if ($item->code && $item->code != md5($item->init_code)) {
                                    return '用户已修改';
                                }

                                return $item->init_code;
                            },
                            'has_bind'   => function ($item) {
                                return $item->user_id ? '是' : '否';
                            },
                            'note',
                            'status_text',
                            'created_at' => function ($item) {
                                return date('Y-m-d H:i:s', $item->created_at);
                            }
                        ]);
                        foreach ($values as $value) {
                            $worksheet->setCellValueByColumnAndRow($col, $row, $value);
                            $worksheet->getStyleByColumnAndRow($col, $row)->getNumberFormat()
                                ->setFormatCode(NumberFormat::FORMAT_TEXT);
                            $worksheet->getCellByColumnAndRow($col, $row)->getStyle()->applyFromArray([
                                'alignment' => [
                                    'horizontal' => Alignment::HORIZONTAL_CENTER,
                                    'vertical'   => Alignment::VERTICAL_CENTER,
                                ]
                            ]);
                            $col++;
                        }
                    }
                });

            // 导出文件
            // Redirect output to a client’s web browser (Excel2007)
            $fileName = date('YmdHis');
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            header('Content-Disposition: attachment;filename="' . $fileName . '.xlsx"');
            header('Cache-Control: max-age=0');
            // If you're serving to IE 9, then the following may be needed
            header('Cache-Control: max-age=1');
            // If you're serving to IE over SSL, then the following may be needed
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');  // always modified
            header('Cache-Control: cache, must-revalidate');  // HTTP/1.1
            header('Pragma: public');  // HTTP/1.0
            $objWriter = IOFactory::createWriter($spreadsheet, 'Xlsx');
            $objWriter->save('php://output');
            exit;
        }
    }
}
